﻿using System.Collections.Generic;
using System.Collections.Specialized;
using System.Dynamic;

using zijian666.Converts.Abstractions;

namespace zijian666.Converts.Dynamic;

/// <summary>
/// 基于 <seealso cref="NameValueCollection" /> 的动态类型
/// </summary>
internal class DynamicNameValueCollection : DynamicObjectBase<NameValueCollection>
{
    public DynamicNameValueCollection(NameValueCollection value!!, IConvertSettings convertSettings)
        : base(value, convertSettings)
    {
    }

    public override IEnumerable<string> GetDynamicMemberNames() => Value!.AllKeys;

    protected override object? this[int index]
    {
        get => index < 0 || index >= Value!.Count ? null : Value![index];
        set => Value![Value.GetKey(index)] = value.Convert<string>(ConvertSettings).Value;
    }

    public override bool TryConvert(ConvertBinder binder, out object? result)
    {
        if ((Value!.Count == 1) && TryChangeType(Value![0], binder.ReturnType, out result))
        {
            return true;
        }
        return TryChangeType(Value, binder.ReturnType, out result);
    }

    public override bool TryGetMember(GetMemberBinder binder, out object? result)
    {
        result = Value![binder.Name];
        if (result is not null)
        {
            if (TryChangeType(result, binder.ReturnType, out result))
            {
                result = CreateDynamic(result);
                return true;
            }
        }

        result = DynamicPrimitive.Null;
        return true;
    }

    public override bool TrySetMember(SetMemberBinder binder, object? value)
    {
        if (IsReadOnly)
        {
            return false;
        }
        Value![binder.Name] = value.To<string>();
        return true;
    }

    private object? Indexer(object[] indexes)
    {
        if ((indexes is null) || (indexes.Length != 1))
        {
            return null;
        }
        var index = indexes[0];
        if (index is string name)
        {
            return Value![name];
        }
        var i = index.To(-1);
        if ((i < 0) || (i >= Value!.Count))
        {
            return null;
        }
        return Value[i];
    }

    public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object? result)
    {
        result = Indexer(indexes);
        if (result is not null)
        {
            if (TryChangeType(result, binder.ReturnType, out result))
            {
                result = CreateDynamic(result);
                return true;
            }
        }

        result = DynamicPrimitive.Null;
        return true;
    }

    public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object? value)
    {
        if (IsReadOnly)
        {
            return false;
        }

        if (indexes.Length != 1)
        {
            return false;
        }
        var index = indexes[0];
        var str = value.To<string>();
        if (index is string name)
        {
            Value![name] = str;
            return true;
        }
        var i = index.To(-1);
        if ((i < 0) || (i >= Value!.Count))
        {
            return false;
        }
        Value[Value.GetKey(i)] = str;
        return true;
    }
}
